{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Picturing vectors in three-dimensional space"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3D Drawing in Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "source": [
    "from draw3d import *"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "source": [
    "draw3d()"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "source": [
    "draw3d(\n",
    "    Points3D((2,2,2),(1,-2,-2)),\n",
    "    Arrow3D((2,2,2)),\n",
    "    Arrow3D((1,-2,-2)),\n",
    "    Segment3D((2,2,2), (1,-2,-2))\n",
    ")"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "source": [
    "draw3d(\n",
    "    Points3D((2,2,2),(1,-2,-2))\n",
    ")"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "source": [
    "draw3d(\n",
    "    Points3D((2,2,2),(1,-2,-2)),\n",
    "    Arrow3D((2,2,2)),\n",
    "    Arrow3D((1,-2,-2)),\n",
    "    Segment3D((2,2,2), (1,-2,-2))\n",
    ")"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "source": [
    "draw3d(\n",
    "    Points3D((2,2,2),(1,-2,-2)),\n",
    "    Arrow3D((2,2,2)),\n",
    "    Arrow3D((1,-2,-2)),\n",
    "    Segment3D((2,2,2), (1,-2,-2)),\n",
    "    Box3D(2,2,2),\n",
    "    Box3D(1,-2,-2)\n",
    ")"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercises"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Draw the 3D arrow and point representing the coordinates $(-1,-2,2)$, as well as the dashed box that makes the arrow look 3D.  Do this drawing by hand as practice, but from now on we’ll use Python to draw for us."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "source": [
    "v = (-1,-2,2)\n",
    "draw3d(\n",
    "    Points3D(v),\n",
    "    Arrow3D(v),\n",
    "    Box3D(*v)\n",
    ")"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Mini project:** There are eight 3D vectors that have every coordinate equal to $+1$ or $-1$.  For instance, $(1,-1,1)$ is one of them.  Plot all of these eight vectors as points.  Then, figure out how to connect them with line segments (using `Segment3D` objects) to form the outline of a cube.  Hint: you’ll need 12 segments in total."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "source": [
    "pm1 = [1,-1]"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "source": [
    "vertices = [(x,y,z) for x in pm1 for y in pm1 for z in pm1]"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "source": [
    "edges = [((-1,y,z),(1,y,z)) for y in pm1 for z in pm1] +\\\n",
    "                [((x,-1,z),(x,1,z)) for x in pm1 for z in pm1] +\\\n",
    "                [((x,y,-1),(x,y,1)) for x in pm1 for y in pm1]"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "source": [
    "draw3d(\n",
    "    Points3D(*vertices,color=blue),\n",
    "    *[Segment3D(*edge) for edge in edges]\n",
    ")"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Vector arithmetic in 3D"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding 3D vectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "source": [
    "def add(*vectors):\n",
    "    by_coordinate = zip(*vectors)\n",
    "    coordinate_sums = [sum(coords) for coords in by_coordinate]\n",
    "    return tuple(coordinate_sums)"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "source": [
    "list(zip(*[(1,1,3),(2,4,-4),(4,2,-2)]))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "source": [
    "[sum(coords) for coords in [(1, 2, 4), (1, 4, 2), (3, -4, -2)]]"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "source": [
    "def add(*vectors):\n",
    "    return tuple(map(sum,zip(*vectors)))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "source": [
    "add((1,1,3),(2,4,-4),(4,2,-2))"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Computing lengths and distances"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "source": [
    "from math import sqrt\n",
    "def length(v):\n",
    "    return sqrt(sum([coord ** 2 for coord in v]))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "source": [
    "length((3,4,12))"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercises"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Draw $(4,0,3)$ and $(-1,0,1)$ as Arrow3D objects, such that they are placed tip-to-tail in both orders in 3D.  What is their vector sum?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "source": [
    "add((4,0,3),(-1,0,1))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "source": [
    "draw3d(\n",
    "    Arrow3D((4,0,3),color=red),\n",
    "    Arrow3D((-1,0,1),color=blue),\n",
    "    Arrow3D((3,0,4),(4,0,3),color=blue),\n",
    "    Arrow3D((-1,0,1),(3,0,4),color=red),\n",
    "    Arrow3D((3,0,4),color=purple)\n",
    ")"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Suppose we set `vectors1=[(1,2,3,4,5), (6,7,8,9,10)]` and `vectors2=[(1,2), (3,4), (5,6)]`.  Without evaluating in Python, what are the results of `len(zip(*vectors1))` and `len(zip(*vectors2))`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "source": [
    "vectors1=[(1,2,3,4,5), (6,7,8,9,10)]"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "source": [
    "vectors2=[(1,2), (3,4), (5,6)]"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "source": [
    "len(list(zip(*vectors1)))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "source": [
    "len(list(zip(*vectors2)))"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Mini project:** The comprehension below creates a list of 24 Python vectors\n",
    "```\n",
    "from math import sin, cos, pi\n",
    "vs = [(sin(pi*t/6), cos(pi*t/6), 1.0/3) for t in range(0,24)]\n",
    "```\n",
    "What is the sum of the 24 vectors?  Draw all 24 of them tip-to-tail as Arrow3D objects."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "source": [
    "from math import sin, cos, pi\n",
    "vs = [(sin(pi*t/6), cos(pi*t/6), 1.0/3) for t in range(0,24)]\n",
    "\n",
    "running_sum = (0,0,0) #<1>\n",
    "arrows = []\n",
    "for v in vs:\n",
    "    next_sum = add(running_sum, v) #2\n",
    "    arrows.append(Arrow3D(next_sum, running_sum)) \n",
    "    running_sum = next_sum\n",
    "print(running_sum)\n",
    "draw3d(*arrows)"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Write a function `scale(scalar,vector)` that returns the input scalar times the input vector.  Specifically, write it so it works on 2D or 3D vectors, or vectors of any number of coordinates."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "source": [
    "def scale(scalar,v):\n",
    "    return tuple(scalar * coord for coord in v)"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Mini project:** The coordinates 3, 4, 12 in any order create a vector of length 13, a whole number. This is unusual because most numbers are not perfect squares, so the square root in the length formula typically returns an irrational number.  Find a different triple of whole numbers that define coordinates of a vector with whole number length."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "source": [
    "def vectors_with_whole_number_length(max_coord=100):\n",
    "    for x in range(1,max_coord):\n",
    "        for y in range(1,x+1):\n",
    "            for z in range(1,y+1):\n",
    "                if length((x,y,z)).is_integer():\n",
    "                    yield (x,y,z)"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "source": [
    "list(vectors_with_whole_number_length())"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Find a vector in the same direction as $(-1,-1,2)$ but which has length 1.  Hint: find the appropriate scalar to multiply the original vector to change its length appropriately."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "source": [
    "length((-1,-1,2))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "source": [
    "s = 1/length((-1,-1,2))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "source": [
    "scale(s,(-1,-1,2))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "source": [
    "length(scale(s,(-1,-1,2)))"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The dot product: measuring alignment of vectors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Computing the dot product"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "source": [
    "def dot(u,v):\n",
    "    return sum([coord1 * coord2 for coord1,coord2 in zip(u,v)])"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dot products by example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "source": [
    "dot((1,0),(0,2))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "source": [
    "dot((0,3,0),(0,0,-5))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "source": [
    "dot((3,4),(2,3))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "source": [
    "dot(scale(2,(3,4)),(2,3))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "source": [
    "dot((3,4),scale(2,(2,3)))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "source": [
    "dot((4,3),(8,6))"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Measuring angles with the dot product"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "source": [
    "from math import cos,pi"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "source": [
    "3 * 2 * cos(75 * pi / 180)"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "source": [
    "def angle_between(v1,v2):\n",
    "    return acos(\n",
    "                dot(v1,v2) /\n",
    "                (length(v1) * length(v2))\n",
    "            )"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Mini project:** Find a vector $\\vec{u}$ of length 3 and a vector $\\vec{v}$ of length 7, such that $\\vec{u} \\cdot \\vec{v} = 21$.  Find another pair of vectors $\\vec{u}$ and $\\vec{v}$ such that $\\vec{u} \\cdot \\vec{v} = -21$.  Finally, find three more pairs of vectors of respective lengths 3 and 7 and show that all of their lengths lie between -21 and 21."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "source": [
    "dot((3,0),(7,0))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "source": [
    "dot((0,3),(0,-7))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "source": [
    "from vectors import to_cartesian\n",
    "from random import random\n",
    "from math import pi\n",
    "\n",
    "def random_vector_of_length(l):\n",
    "    return to_cartesian((l, 2*pi*random()))\n",
    "\n",
    "pairs = [(random_vector_of_length(3), random_vector_of_length(7))\n",
    "            for i in range(0,3)]\n",
    "for u,v in pairs:\n",
    "    print(\"u = %s, v = %s\" % (u,v))\n",
    "    print(\"length of u: %f, length of v: %f, dot product :%f\" %\n",
    "                (length(u), length(v), dot(u,v)))"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Let $\\vec{u}$ and $\\vec{v}$ be vectors, with $|\\vec{u}| = 3.61$ and $|\\vec{v}| = 1.44$.  If the angle between $\\vec{u}$ and $\\vec{v}$ is 101.3 degrees, what is $\\vec{u} ∙ \\vec{v}$?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "source": [
    "3.61 * 1.44 * cos(101.3 * pi / 180)"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Mini Project:** Find the angle between $(3,4)$ and $(4,3)$ by converting them to polar coordinates and taking the difference of the angles.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "source": [
    "from vectors import to_polar\n",
    "r1,t1 = to_polar((4,3))\n",
    "r2,t2 = to_polar((3,4))\n",
    "t1-t2"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "source": [
    "t2-t1"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The cross product: measuring oriented area"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Computing the cross product of 3D vectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "source": [
    "def cross(u, v):\n",
    "    ux,uy,uz = u\n",
    "    vx,vy,vz = v\n",
    "    return (uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx)"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercises"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Use the Python cross function to compute $(0,0,1) \\times \\vec{v}$ for a few different values of a second vector $\\vec{v}$.  What is the $z$-coordinate of each result, and why?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "source": [
    "cross((0,0,1),(1,2,3))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "source": [
    "cross((0,0,1),(-1,-1,0))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "source": [
    "cross((0,0,1),(1,-1,5))"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Rendering a 3D object in 2D"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Defining a 3D object with vectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "source": [
    "octahedron = [\n",
    "    [(1,0,0), (0,1,0), (0,0,1)],\n",
    "    [(1,0,0), (0,0,-1), (0,1,0)],\n",
    "    [(1,0,0), (0,0,1), (0,-1,0)],\n",
    "    [(1,0,0), (0,-1,0), (0,0,-1)],\n",
    "    [(-1,0,0), (0,0,1), (0,1,0)],\n",
    "    [(-1,0,0), (0,1,0), (0,0,-1)],\n",
    "    [(-1,0,0), (0,-1,0), (0,0,1)],\n",
    "    [(-1,0,0), (0,0,-1), (0,-1,0)],\n",
    "]"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "source": [
    "def vertices(faces):\n",
    "    return list(set([vertex for face in faces for vertex in face]))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "source": [
    "def component(v,direction):\n",
    "    return (dot(v,direction) / length(direction))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "source": [
    "def vector_to_2d(v):\n",
    "    return (component(v,(1,0,0)), component(v,(0,1,0)))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "source": [
    "def face_to_2d(face):\n",
    "    return [vector_to_2d(vertex) for vertex in face]"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Orienting faces and shading"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "source": [
    "blues = matplotlib.cm.get_cmap('Blues')"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "source": [
    "def unit(v):\n",
    "    return scale(1./length(v), v)"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "source": [
    "def normal(face):\n",
    "    return(cross(subtract(face[1], face[0]), subtract(face[2], face[0])))"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "source": [
    "from vectors import *\n",
    "from draw2d import *"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "source": [
    "def render(faces, light=(1,2,3), color_map=blues, lines=None):\n",
    "    polygons = []\n",
    "    for face in faces:\n",
    "        unit_normal = unit(normal(face)) #1\n",
    "        if unit_normal[2] > 0: #2\n",
    "            c = color_map(1 - dot(unit(normal(face)), unit(light))) #3\n",
    "            p = Polygon2D(*face_to_2d(face), fill=c, color=lines) #4\n",
    "            polygons.append(p)\n",
    "    draw2d(*polygons,axes=False, origin=False, grid=None)"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "source": [
    "render(octahedron, color_map=matplotlib.cm.get_cmap('Blues'), lines=black)"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "source": [
    "def split(face):\n",
    "    midpoints = [unit(add(face[i], face[(i+1)%len(face)])) for i in range(0,len(face))]\n",
    "    triangles = [(face[i], midpoints[i], midpoints[(i-1)%len(face)]) for i in range(0,len(face))]\n",
    "    return [midpoints] + triangles\n",
    "\n",
    "def rec_split(faces, depth=0):\n",
    "    if depth == 0:\n",
    "        return faces\n",
    "    else:\n",
    "        return rec_split([new_face for face in faces for new_face in split(face)], depth-1)\n",
    "\n",
    "# NICE SPHERE!\n",
    "def sphere_approx(n):\n",
    "    return rec_split(octahedron,n)"
   ],
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "source": [
    "render(sphere_approx(3), lines='k')"
   ],
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercises"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Mini project:** Find pairs of vectors defining each of the 12 edges of the octahedron, and draw all of the edges in Python."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "source": [
    "top = (0,0,1)\n",
    "bottom = (0,0,-1)\n",
    "xy_plane = [(1,0,0),(0,1,0),(-1,0,0),(0,-1,0)]\n",
    "edges = [Segment3D(top,p) for p in xy_plane] +\\\n",
    "            [Segment3D(bottom, p) for p in xy_plane] +\\\n",
    "            [Segment3D(xy_plane[i],xy_plane[(i+1)%4]) for i in range(0,4)] \n",
    "draw3d(*edges)"
   ],
   "outputs": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
